package org.smart4j.framework.common.aop;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;

/**
 * 切面代理
 *
 * @author YooLin1c
 * @version 1.0.0
 * @since 2018-02-03 14:20
 */
@Slf4j
public abstract class AspectProxy implements Proxy {
    /**
     * 代理增强
     *
     * @param proxyChain 代理链
     * @return 目标方法返回值
     * @throws Throwable 异常
     */
    @Override
    public Object doProxy(ProxyChain proxyChain) throws Throwable {
        Object result;
        Class<?> clazz = proxyChain.getTargetClass();
        Object[] args = proxyChain.getMethodParams();
        Method method = proxyChain.getTargetMethod();
        //初始化方法
        begin();
        try {
            //拦截执行通知
            if (intercept(clazz, method, args)) {
                //前置通知
                before(clazz, method, args);
                //执行下一个代理链，如果执行完则执行原目标方法
                result = proxyChain.doProxyChain();
                //返回通知
                after(clazz, method, args, result);
            } else {
                //不拦截，不执行通知
                result = proxyChain.doProxyChain();
            }
        } catch (Exception e) {
            log.error("proxy failed!", e);
            //异常通知
            if (intercept(clazz, method, args)) {
                error(clazz, method, args, e);
            }
            throw e;
        } finally {
            //后置通知
            end();
        }
        return result;
    }

    /**
     * 初始化（钩子）
     */
    protected void begin() {
    }

    /**
     * 是否进行拦截（钩子）
     *
     * @param clazz  目标类
     * @param method 目标方法
     * @param args   方法参数
     * @return true 拦截 false 不拦截
     * @throws Throwable 异常
     */
    public boolean intercept(Class<?> clazz, Method method, Object[] args) throws Throwable {
        return true;
    }

    /**
     * 前置增强（钩子）
     *
     * @param clazz  目标类
     * @param method 目标方法
     * @param args   方法参数
     * @throws Throwable 异常
     */
    public void before(Class<?> clazz, Method method, Object[] args) throws Throwable {
    }

    /**
     * 后置增强（钩子）
     *
     * @param clazz  目标类
     * @param method 目标方法
     * @param args   方法参数
     * @param result 方法返回值
     * @throws Throwable 异常
     */
    public void after(Class<?> clazz, Method method, Object[] args, Object result) throws Throwable {
    }

    /**
     * 异常增强（钩子）
     *
     * @param clazz  目标类
     * @param method 目标方法
     * @param args   方法参数
     * @param error  方法抛出的异常
     * @throws Throwable 异常
     */
    public void error(Class<?> clazz, Method method, Object[] args, Throwable error) throws Throwable {
    }

    /**
     * 结束方法（钩子）
     */
    public void end() {
    }
}
